package com.zbest.zpay.acctrans.component;

import java.util.Date;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.zbest.common.lang.base.Money;
import com.zbest.common.lang.util.CoreDateUtils;
import com.zbest.zpay.acctrans.common.exception.AccTransRuntimeException;
import com.zbest.zpay.acctrans.dal.mapper.AccountBalanceMapper;
import com.zbest.zpay.acctrans.dal.mapper.AccountDetailMapper;
import com.zbest.zpay.acctrans.dal.mapper.AccountHoldMapper;
import com.zbest.zpay.acctrans.dal.model.AccountBalance;
import com.zbest.zpay.acctrans.dal.model.AccountDetail;
import com.zbest.zpay.acctrans.dal.model.AccountHold;
import com.zbest.zpay.acctrans.dal.model.AccountInf;
import com.zbest.zpay.acctrans.dal.model.TransJnl;
import com.zbest.zpay.acctrans.enums.CapStsFlg;
import com.zbest.zpay.acctrans.enums.DebitCreditHoldFlag;
import com.zbest.zpay.acctrans.enums.HoldStatus;
import com.zbest.zpay.acctrans.enums.UpdBalFlg;
import com.zbest.zpay.acctrans.enums.VchNoType;
import com.zbest.zpay.acctrans.enums.biz.AcctransBizCode;

public class MainAccountUnHoldComponent {

    private static final Logger logger = LoggerFactory
            .getLogger(MainAccountUnHoldComponent.class);

    private Money zero = new Money(0, Money.DEFAULT_CURRENCY);

    @Autowired
    private AccountBalanceMapper accountBalanceMapper;

    @Autowired
    private AccountDetailMapper accountDetailMapper;

    @Autowired
    private AccountHoldMapper accountHoldMapper;

    public void execute(TransJnl transJnl, AccountInf accountInf) {
        logger.info("[UNHOLD ACCOUNT START!]");
        if (transJnl == null) {
            logger.info("AccountTransJnl不能为空");
            throw new AccTransRuntimeException(AcctransBizCode.ACT_FIELD_NOT_NULL, "transJnl不能为空");
        }
        String actNo = accountInf.getActNo();
        Money unHldAmt = new Money(transJnl.getHldAmt(), Money.DEFAULT_CURRENCY);
        String hldNo = transJnl.getHldNo();
        logger.info("[查询主账户余额信息]");
        AccountBalance mainAccountBalance = null;
        /** 在主账户余额信息表中判断是否存在该账户的余额信息,如果存在再 for update该记录，避免死锁 */
        long retNum = accountBalanceMapper.qryCntByActNo(actNo);
        if (retNum == 1) {
            mainAccountBalance = accountBalanceMapper.qryByActNoForUpd(actNo);
        }
        if (mainAccountBalance == null) {
            throw new AccTransRuntimeException(AcctransBizCode.ACT_ACCOUNT_BAL_NOT_EXIST,
                    "主账户余额信息不存在");
        }

        logger.info("[查询主账户冻结解冻信息]");
        AccountHold mainAccountHold = null;
        long retCod = accountHoldMapper.queryCntByHldNo(hldNo);
        if (retCod == 1) {
            mainAccountHold = accountHoldMapper.queryHoldInfForUpd(hldNo);
        } else {
            throw new AccTransRuntimeException(AcctransBizCode.ACT_ACCOUNT_HOLDNO_NOT_EXIST,
                    "冻结编号不存在");
        }
        if (!StringUtils.equals(mainAccountHold.getActNo(), accountInf.getActNo())) {
            throw new AccTransRuntimeException(AcctransBizCode.ACT_ACCOUNT_HOLD_ACCOUNTDIFF,
                    "同冻结编号下追加的冻结账户必须一致");
        }

        Money hldBal = new Money(mainAccountHold.getHldBal(), Money.DEFAULT_CURRENCY);
        if (unHldAmt.compareTo(zero) <= 0) {
            unHldAmt = new Money(mainAccountHold.getHldBal(), Money.DEFAULT_CURRENCY);
        } else if (unHldAmt.compareTo(hldBal) <= 0) {
            hldBal = hldBal.subtract(unHldAmt);
        } else if (unHldAmt.compareTo(hldBal) > 0) {
            logger.info("[解冻金额大于冻结金额]");
            throw new AccTransRuntimeException(AcctransBizCode.ACT_ACCOUNT_UNHOLDAMT_FAIL,
                    "解冻金额大于原始冻结金额");
        }

        updAccountBalance(transJnl, mainAccountHold, mainAccountBalance, unHldAmt);
        updMainActBalHoldTalbe(mainAccountHold, hldBal);

        writeMainActDrCrDetail(transJnl, mainAccountHold, mainAccountBalance);

    }

    public void updAccountBalance(TransJnl accountTransJnl, AccountHold mainAccountHold,
                                  AccountBalance mainAccountBalance, Money unHldAmt) {
        Money uavaBal = new Money(mainAccountBalance.getUavaBal(), Money.DEFAULT_CURRENCY).subtract(unHldAmt);

        //		Money notTxAmt = new Money(mainAccountHold.getNotTxAmt(),
        //				Currency.getInstance(Money.DEFAULT_CURRENCY_CODE))
        //				.subtract(unHoldAmt);

        //		Money notTxAvaBal = new Money(mainAccountBalance.getNotTxAvaBal(),
        //				Currency.getInstance(Money.DEFAULT_CURRENCY_CODE))
        //				.add(notTxAmt);

        Money notTxAvaBal = new Money(mainAccountBalance.getNotTxAvaBal(), Money.DEFAULT_CURRENCY);

        Money lastBalAmt = new Money(mainAccountBalance.getLastActBal(), Money.DEFAULT_CURRENCY);
        String lastAcDate = mainAccountBalance.getUpdDat();
        Money lastUavaBal = new Money(mainAccountBalance.getLastUavaBal(), Money.DEFAULT_CURRENCY);
        String actPostDt = accountTransJnl.getActDat();
        if (Long.valueOf(actPostDt) > Long.valueOf(lastAcDate)) {
            lastBalAmt = new Money(mainAccountBalance.getCurActBal(), Money.DEFAULT_CURRENCY);
            lastUavaBal = new Money(mainAccountBalance.getUavaBal(), Money.DEFAULT_CURRENCY);
            lastAcDate = actPostDt;
        }
        mainAccountBalance.setLastUavaBal(lastUavaBal.getCent());
        mainAccountBalance.setLastActBal(lastBalAmt.getCent());
        mainAccountBalance.setUavaBal(uavaBal.getCent());
        mainAccountBalance.setUpdDat(lastAcDate);
        mainAccountBalance.setNotTxAvaBal(notTxAvaBal.getCent());

        int retCd = accountBalanceMapper.updateBalByActNo(mainAccountBalance);
        if (retCd == 0) {
            throw new AccTransRuntimeException(AcctransBizCode.ACT_ACCOUNT_UPDBAL_FAIL,
                    "更新主账户余额失败");
        }

    }

    public void updMainActBalHoldTalbe(AccountHold mainAccountHold, Money hldBal) {
        String hldSts = mainAccountHold.getHldSts();
        if (hldBal.compareTo(zero) == 0)
            hldSts = HoldStatus.HOLD_NORMAL.getCode();
        int retCd = accountHoldMapper.updateBalByHldNo(hldSts, hldBal.getCent(), mainAccountHold.getHldNo());
        if (retCd == 0) {
            throw new AccTransRuntimeException(AcctransBizCode.ACT_ACCOUNT_NOT_EXIST_HOLD,
                    "不存在该冻结编号信息");
        }
    }

    public void writeMainActDrCrDetail(TransJnl transJnl,
                                       AccountHold mainAccountHold,
                                       AccountBalance mainAccountBalance) {
        logger.info("[Class of UnHoldAccount writ debit or credit detail!]");

        String vchNo = (StringUtils.isBlank(transJnl.getVchNo())) ? transJnl
                .getJrnNo() : transJnl.getVchNo();

        AccountDetail mainAccountDetail = new AccountDetail();
        long lastActBal = mainAccountBalance.getLastActBal();
        long lastUavaBal = mainAccountBalance.getLastUavaBal();
        Money objLastActBal = new Money(lastActBal, Money.DEFAULT_CURRENCY);
        Money objLastUavaBal = new Money(lastUavaBal, Money.DEFAULT_CURRENCY);
        Money objLastAvaBal = objLastActBal.subtract(objLastUavaBal);
        mainAccountDetail.setSysDat(CoreDateUtils.yyyymmdd(new Date()));
        mainAccountDetail.setSysTim(CoreDateUtils.hh24miss(new Date()));
        mainAccountDetail.setJrnNo(transJnl.getJrnNo());
        mainAccountDetail.setJrnSeq(transJnl.getJrnSeq());
        mainAccountDetail.setActNo(mainAccountBalance.getActNo());
        mainAccountDetail.setActTyp(mainAccountBalance.getActTyp());
        mainAccountDetail.setOldTxDt(transJnl.getOldTxDt());
        mainAccountDetail.setOldTxTm(transJnl.getOldTxTm());
        mainAccountDetail.setActDat(transJnl.getActDat());
        mainAccountDetail.setTxCd(transJnl.getHldTxCd());
        mainAccountDetail.setBusTyp(transJnl.getHldBusTyp());
        mainAccountDetail.setDcFlg(DebitCreditHoldFlag.UNHOLD_FLAG.getCode());
        mainAccountDetail.setTxDesc(transJnl.getTxDesc());
        mainAccountDetail.setOrdTyp(transJnl.getOrdTyp());
        mainAccountDetail.setOrdNo(transJnl.getOrdNo());
        mainAccountDetail.setUsrId(transJnl.getCrUsrId());
        mainAccountDetail.setTxAmt(transJnl.getOrdAmt());
        mainAccountDetail.setFeeAmt(transJnl.getFeeAmt());
        mainAccountDetail.setMercId(transJnl.getMercId());
        mainAccountDetail.setVchNoTyp(transJnl.getVchNoTyp());
        mainAccountDetail.setVchNo(transJnl.getVchNo());
        mainAccountDetail.setRmk(transJnl.getTxDesc());
        mainAccountDetail.setBusCnl(transJnl.getBusCnl());
        mainAccountDetail.setSysCnl(transJnl.getSysCnl());
        mainAccountDetail.setHldAmt(transJnl.getHldAmt());
        mainAccountDetail.setHldNo(transJnl.getHldNo());
        mainAccountDetail.setBal(mainAccountBalance.getCurActBal());
        mainAccountDetail.setNotTxAmt(mainAccountBalance.getNotTxAvaBal());
        mainAccountDetail.setUavaBal(mainAccountBalance.getUavaBal());
        mainAccountDetail.setLastAvaBal(objLastAvaBal.getCent());
        mainAccountDetail.setMainCdSts(CapStsFlg.CAP_STATUS_NORMAL.getCode());
        mainAccountDetail.setUpdBalFlg(UpdBalFlg.IS_UPDATE.getCode());
        mainAccountDetail.setBal(mainAccountBalance.getCurActBal());

        if (StringUtils.isBlank(transJnl.getVchNoTyp()))
            mainAccountDetail.setVchNoTyp(VchNoType.VOUCHER_TYPE_JRN.getCode());
        else
            mainAccountDetail.setVchNoTyp(transJnl.getVchNoTyp());
        mainAccountDetail.setVchNo(vchNo);
        accountDetailMapper.insert(mainAccountDetail);
    }

}
